package com.osfw.framework.advice;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageInfo;
import com.osfw.framework.annotation.RestfulMessage;
import com.osfw.framework.core.domain.RestfulResult;
import com.osfw.framework.core.page.TableDataInfo;
import com.osfw.framework.utils.StringUtils;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.core.env.Environment;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.AnnotatedElement;
import java.util.Arrays;
import java.util.List;

@ControllerAdvice(
        annotations = {RestController.class, Controller.class}
)
public class RestfulResultHander implements ResponseBodyAdvice {
    private static final Class[] annos = new Class[]{RequestMapping.class, GetMapping.class, PostMapping.class, DeleteMapping.class, PutMapping.class};
    boolean formatPage = true;
    @Autowired
    Environment env;

    public RestfulResultHander() {
    }

    public boolean supports(MethodParameter returnType, Class converterType) {
        AnnotatedElement element = returnType.getAnnotatedElement();
        return Arrays.stream(annos).anyMatch((anno) -> {
            return anno.isAnnotation() && element.isAnnotationPresent(anno);
        });
    }

    @SneakyThrows
    public Object beforeBodyWrite(@Nullable Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof RestfulResult || (body instanceof List && returnType.getGenericParameterType().getTypeName().contains("Ztree"))) {
            return body;
        } else if (body instanceof String) {
            ObjectMapper om = new ObjectMapper();
            return om.writeValueAsString(RestfulResult.success(body));
        } else if (body instanceof PageInfo) {
            return getDataTable(((PageInfo<?>) body).getList());
        } else {
            AnnotatedElement element = returnType.getAnnotatedElement();

            if (selectedConverterType.isAnnotationPresent(Controller.class) && !element.isAnnotationPresent(ResponseBody.class)) {
                return body;
            }

            if (element.isAnnotationPresent(RestfulMessage.class)) {
                boolean ignore = (element.getAnnotation(RestfulMessage.class)).ignore();
                if (ignore) {
                    return body;
                }
            }

            if (this.formatPage && body instanceof Page) {
                Page page = (Page) body;
                com.baomidou.mybatisplus.extension.plugins.pagination.Page mpPage = new com.baomidou.mybatisplus.extension.plugins.pagination.Page((long) (page.getNumber() + 1), (long) page.getSize(), true);
                mpPage.setRecords(page.getContent());
                body = mpPage;
            }

            HttpHeaders headers = request.getHeaders();
            List<String> list = headers.get("Keep-Original");
            if (list != null && list.contains("Keep-Original")) {
                return body;
            } else {
                String msg = null;
                if (element.isAnnotationPresent(RestfulMessage.class)) {
                    String value = element.getAnnotation(RestfulMessage.class).value();
                    if (value != null) {
                        value = value.trim();
                        if (value.startsWith("${") && value.endsWith("}")) {
                            value = value.substring(2, value.length() - 1);
                            String[] separator = StringUtils.splitByWholeSeparator(value, ":");
                            String key = separator[0];
                            String defaultValue = separator.length > 1 ? separator[1] : null;
                            msg = this.env.getProperty(key, defaultValue);
                        } else {
                            msg = value;
                        }
                    }
                }

                if (msg == null) {
                    if (element.isAnnotationPresent(PutMapping.class) || element.isAnnotationPresent(PatchMapping.class)) {
                        msg = "修改成功";
                    } else if (element.isAnnotationPresent(DeleteMapping.class)) {
                        msg = "删除成功";
                    } else {
                        msg = "操作成功";
                    }
                }

                return RestfulResult.success(msg, body);
            }
        }
    }

    /**
     * 响应请求分页数据
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    protected TableDataInfo getDataTable(List<?> list) {
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(0);
        rspData.setRows(list);
        rspData.setTotal(new PageInfo(list).getTotal());
        return rspData;
    }
}

